package goo

import (
	"fmt"
	"html/template"
	"log"
	"net/http"
	"strings"
	"time"
)

type Context struct {
	Request      *http.Request
	Writer       *http.ResponseWriter
	attrValue    map[string]interface{}
	requestValue map[string]string
}

func (ctx *Context) GetAttr(name string) interface{} {
	return ctx.attrValue[name]
}

func (ctx *Context) GetAttrWithDefault(name string, defaultValue interface{}) interface{} {
	value := ctx.attrValue[name]
	if value == nil {
		return defaultValue
	}
	return value
}

func (ctx *Context) GetAttrToStr(name string) string {
	value := ctx.attrValue[name]
	return value.(string)
}

func (ctx *Context) SetAttr(name string, value interface{}) *Context {
	ctx.attrValue[name] = value
	return ctx
}

func (ctx *Context) RemoveAttr(name string) *Context {
	delete(ctx.attrValue, name)
	return ctx
}

func (ctx *Context) SetAttrs(maps map[string]interface{}) *Context {
	for k, v := range maps {
		ctx.SetAttr(k, v)
	}
	return ctx
}

func (ctx *Context) GetAttrNames() (names []string) {
	names = make([]string, 0)
	for k := range ctx.attrValue {
		names = append(names, k)
	}
	return names
}

func (ctx *Context) GetPara(name string) string {
	if strings.HasPrefix(name, ":") {
		return ctx.requestValue[name]
	}
	return ctx.Request.FormValue(name)
}

func (ctx *Context) GetParaWithDefault(name string, defaultValue string) string {
	value := ""
	if strings.HasPrefix(name, ":") {
		value = ctx.requestValue[name]
	} else {
		value = ctx.Request.FormValue(name)
	}
	if value == "" {
		return defaultValue
	}
	return value
}

func (ctx *Context) GetParaMaps() (result map[string][]string) {
	result = make(map[string][]string)
	_ = ctx.Request.ParseForm()
	for k, v := range ctx.Request.Form {
		result[k] = v
	}
	return result
}

func (ctx *Context) GetParaMap() (result map[string]string) {
	result = make(map[string]string)
	_ = ctx.Request.ParseForm()
	for k, v := range ctx.Request.Form {
		result[k] = v[0]
	}
	for k, v := range ctx.requestValue {
		result[k] = v
	}
	return result
}

func (ctx *Context) GetParaNames() (names []string) {
	names = make([]string, 0)
	_ = ctx.Request.ParseForm()
	for k := range ctx.Request.Form {
		names = append(names, k)
	}
	for k := range ctx.requestValue {
		names = append(names, k)
	}
	return names
}

func (ctx *Context) GetParaValues() (values []string) {
	values = make([]string, 0)
	_ = ctx.Request.ParseForm()
	for _, v := range ctx.Request.Form {
		values = append(values, v[0])
	}
	for _, v := range ctx.requestValue {
		values = append(values, v)
	}
	return values
}

func (ctx *Context) GetHeader(name string) string {
	return ctx.Request.Header.Get(name)
}

func (ctx *Context) SetHeader(name string, value string) *Context {
	(*ctx.Writer).Header().Set(name, value)
	return ctx
}

func (ctx *Context) GetSession(name string) interface{} {
	return nil
}

func (ctx *Context) SetSession(name string, value interface{}) *Context {
	session := SessionMangerInstance().Provider.GetSession(ctx)
	session.Set(name, value)
	return ctx
}

func (ctx *Context) RemoveSession(name string) *Context {
	return ctx
}

func (ctx *Context) GetCookie(name string) *http.Cookie {
	cookie, err := ctx.Request.Cookie(name)
	if err != nil {
		return nil
	}
	return cookie
}

func (ctx *Context) SetCookie(cookie *http.Cookie) *Context {
	http.SetCookie(*ctx.Writer, cookie)
	return ctx
}

func (ctx *Context) GetCookieVal(name string) string {
	cookie, err := ctx.Request.Cookie(name)
	if err != nil {
		return ""
	}
	return cookie.Value
}

func (ctx *Context) SetCookieVal(name string, value string) *Context {
	ad, _ := time.ParseDuration("24h")
	cookie := &http.Cookie{Name: name, Value: value, Expires: time.Now().Add(ad * 365)}
	http.SetCookie(*ctx.Writer, cookie)
	return ctx
}

func (ctx *Context) SetCookieValWithHttpOnly(name string, value string) *Context {
	cookie := &http.Cookie{Name: name, Value: value, HttpOnly: true}
	http.SetCookie(*ctx.Writer, cookie)
	return ctx
}

func (ctx *Context) RemoveCookie(name string) *Context {
	cookie := &http.Cookie{Name: name, Value: "", Expires: time.Now()}
	http.SetCookie(*ctx.Writer, cookie)
	return ctx
}

func (ctx *Context) RenderFile(filePath string) {
	http.ServeFile(*ctx.Writer, ctx.Request, filePath)
}

func (ctx *Context) RenderHtml(page string) {
	t, err := template.ParseFiles(page + ".html")
	if err != nil {
		log.Fatal(err)
	}
	t.Execute(*ctx.Writer, ctx.attrValue)
}

func (ctx *Context) RenderText(text string) {
	fmt.Fprintf(*ctx.Writer, text)
}

func (ctx *Context) RenderJsonStr(json string) {
	fmt.Fprintf(*ctx.Writer, json)
}

func (ctx *Context) RenderJson(json interface{}) {}
